#include "dicom/handler/login_handler.h"

#include "surbasic/AccessToken.h"
#include "surbasic/surbasic.h"
#include "surbasic/Digestor.h"

#include <boost/bind.hpp>
#include <gwbase/base/util.h>
#include <gwbase/base/logging.h>
#include <gwbase/base/random.h>
#include <gwbase/base/thread.h>
#include <json/json.h>
#include "dicom/web_server.h"
#include "dicom/session.h"
#include "dicom/handler/handler_common.h"
#include "dicom/upload/cloud_login.h"
#include "dicom/sync_manager.h"

namespace dicom {

static const char* kSurMDAccountType = "surmd";
static const char* kSurMDAccountPrefix = "SMARF6458304_";

static HttpHandler* CreateLoginHander(onion_request* req,
                                      const DicomConf* conf) {
  return new LoginHandler(req, conf);
}

void LoginHandler::RegisterHandler(WebServer* s, const DicomConf* conf) {
  s->AddHandler("/api/login", "GET", boost::bind(CreateLoginHander, _1, conf));

  s->AddHandler("/api/logout", "GET", boost::bind(CreateLoginHander, _1, conf));
}

int LoginHandler::HandleRequest(onion_request* req, onion_response* resp) {
  Status s;
  if (GetReqPath(req) == "/api/logout") {
    CredentialPtr c;
    std::string t;
    s = CheckToken(req, &c, &t);
    if (!s.ok()) {
      SendSimpleResponse(resp, 401, "authorization error");
      return OCS_PROCESSED;
    }
    LOG_INFO << "logout: " << t << " : " << c->email;
    GetGateway()->session_mgr()->Logout(t);
    Json::Value v;
    v["code"] = 0;
    v["message"] = "success";
    SendJsonResult(resp, 200, v);
    LOG_INFO << "user: " << c->email << " LOGOUT";
    LogHippaAccountOperation(OP_LOGOUT, c->email, c->ukey_id);
    return OCS_PROCESSED;
  }

  // do login
  std::string name = GetQueryString(req, "name");
  std::string password = GetQueryString(req, "password");
  std::string account_type = GetQueryString(req, "atype");
  std::string ukey_id = GetQueryString(req, "ukey_id");
  if (name.empty() || password.empty()) {
    SendSimpleResponse(resp, 401, "name/password is empty");
    return OCS_PROCESSED;
  }

  if (!account_type.empty() &&
      ::strcmp(account_type.c_str(), kSurMDAccountType) == 0) {
    name = std::string(kSurMDAccountPrefix) + name;
  }

  AccessToken surdoc_token;
  int64_t surdoc_key;
  std::string root_dir_id;
  std::string server = conf_->GetCloudServer();
  LOG_INFO << "login to surcloud " << server << ": " << name;
  s = LoginToCloud(server, name, password, &surdoc_token, &surdoc_key,
                   &root_dir_id);
  if (!s.ok()) {
    SendSimpleResponse(resp, 401, s.ToString());
    return OCS_PROCESSED;
  }

  SessionManager* mgr = GetGateway()->session_mgr();
  std::string token = GenToken();
  mgr->Save(token, surdoc_token.access_token, name, password, ukey_id,
            root_dir_id, surdoc_token.privatekey, surdoc_key);

  DmvDBPtr db = GetGateway()->dmv_mgr()->GetDB(name);
  db->InsertRootDirNode("0", root_dir_id);

  GetGateway()->sync_mgr()->AddNewUser(name);
  LogHippaAccountOperation(OP_LOGIN, name, ukey_id);

  Json::Value v;
  v["code"] = 0;
  v["message"] = "success";
  v["token"] = token;
  v["name"] = name;
  SendJsonResult(resp, 200, v);
  return OCS_PROCESSED;
}
}
